# !/usr/bin/env python
# @Time    : 2021/1/18 17:41
# @Author  : qiaoc
# @File    : Ocr.py
# @Desc    : OCR识别调用类
import json
import requests
import hashlib
import base64
from ocr.OcrUtils import *
from dao.PyMysql import *
from log.mainModule import *

class Ocr:

    ''' 定义OCR图像识别操作类 '''
    def __init__(self):
        pass

    #调用OCR接口，并返回识别数据
    @staticmethod
    def callOcrApi(headerData, base64_data, isTable=False):
        # 测试
        # template_url = 'https://mage.uibot.com.cn/v1/document/ocr/template'
        # table_url = 'https://mage.uibot.com.cn/v1/mage/ocr/table'
        # 正式环境测试版
        # template_url = 'http://10.221.167.89:82/v1/document/ocr/template'
        # table_url = 'http://10.221.167.89:82/v1/mage/ocr/table'
        # 正式环境
        # template_url = 'http://10.221.153.27:82/v1/document/ocr/template'
        # table_url = 'http://10.221.153.27:82/v1/mage/ocr/table'
        template_url = ConfigEnum.ocr_template_url.value
        table_url =  ConfigEnum.ocr_table_url.value
        url = template_url
        body = {"img_base64": base64_data}
        if isTable:
            url = table_url
            body = {"img_base64": [base64_data]
                    }
        headers = {'content-type': "application/json",
                   'Api-Auth-nonce': headerData['Api-Auth-nonce'],
                   'Api-Auth-pubkey': headerData['Api-Auth-pubkey'],
                   'Api-Auth-timestamp': headerData['Api-Auth-timestamp'],
                   'Api-Auth-sign': headerData['Api-Auth-sign']}
        # 这里有个细节，如果body需要json形式的话，需要做处理
        # 可以是data = json.dumps(body)
        try:
            response = requests.post(url, data=json.dumps(body), headers=headers)
            if response.status_code != 200:
                raise Exception(response.status_code,'OCR服务器异常！')
            result = response.text
            result = json.loads(result)
        except Exception as e:
            print('出现异常:', e)


        # 返回信息
        # print(result)
        # 判断接口调用是否存在异常
        # if result["code"] == 0:
        #     # print("成功")
        # else:
        #     print("失败")
        # 返回响应头
        # print(response.status_code)
        return result



    def getHeaderData(self,file_type):
        '''
            根据文件类型，封装模板环境头信息
        :param file_type:
        :return:
        '''

        # 默认使用表格识别
        # 测试
        # api_pubkey = "WOteEt2WvwakWWFGwmqW3qcA"
        # app_secretkey = "1T8vmgh56QEnxQ7yqLmMa05laYkpnzRI"
        # 正式

        api_pubkey = ConfigEnum.ocr_api_pubkey.value
        app_secretkey = ConfigEnum.ocr_app_secretkey.value
        is_table = True
        # 下面是自定义模板的单据类型
        if file_type == 1 or file_type == 5 or file_type == 6 or file_type == 7 or file_type == 11:
            # 内蒙移动-呼和浩特类型1
            is_table = False
            # 测试
            # api_pubkey = "e4y2G5T6LW31fvOakQmC5GoT"
            # app_secretkey = "JHg8IWK7kdW84Mc5r1EjPMYEOHC0NXRp"
            # 正式
            api_pubkey =  ConfigEnum.ocr_hs_api_pubkey
            app_secretkey = ConfigEnum.ocr_hs_app_secretkey
        # elif file_type == 4:
        #     # 内蒙移动-锡盟类型1
        #     is_table = False
        #     # 测试
        #     api_pubkey = "0xIzUlCC7OAJfvBGCgUwOLqh"
        #     app_secretkey = "DzFY5TApJzQz3nhYONeC4bmNoowKg9kn"
            # 正式
            # api_pubkey = "JpdTvN1t1jw3Xdsbyufde3MI"
            # app_secretkey = "MfRreuk6nOCdpQWUloxX0pa53oGBQL4V"
        return self.GenerateHeader(api_pubkey, app_secretkey),is_table

    # 获取OCR接口header信息
    @staticmethod
    def GenerateHeader(api_auth_pubkey, app_auth_secretkey):
        api_auth_timestamp = str(int(time.time()))
        api_auth_nounce = "".join(random.sample(string.ascii_letters + string.digits, 10))
        HeaderDict = dict()
        prefix = "Value Exception"
        if api_auth_pubkey == "":
            raise Exception("{0}, the api_auth_pubkey must not be empty".format(prefix))
        if app_auth_secretkey == "":
            raise Exception("{0}, the app_auth_secret_key must not be empty".format(prefix))
        prefix = "Type Exception"
        if not isinstance(api_auth_pubkey, str):
            raise Exception("{0}, the type of api_auth_pubkey must be string".format(prefix))
        if not isinstance(app_auth_secretkey, str):
            raise Exception("{0}, the type of app_auth_secretkey must be string".format(prefix))
        HeaderDict["Api-Auth-nonce"] = api_auth_nounce
        HeaderDict["Api-Auth-pubkey"] = api_auth_pubkey
        HeaderDict["Api-Auth-timestamp"] = api_auth_timestamp
        token_name = hashlib.sha1()
        token_key = api_auth_nounce + api_auth_timestamp + app_auth_secretkey
        token_name.update(token_key.encode("utf-8"))
        HeaderDict["Api-Auth-sign"] = token_name.hexdigest()
        return HeaderDict


    # 获取OCR类型
    @staticmethod
    def getOcrType(data):
        """
        分析识别OCR结果内容，得到票据的类型:\r\n
            1:呼和浩特1， 2：呼和浩特2,  3：呼和浩特3， 4：锡盟1， 5：锡盟2， 6：锡盟3， 7：锡盟4， 8：锡盟5
        """
        key_words = ['电力客户电费收据', '供电局所辖基站电费明细', '内蒙古托县移动基站电费', '大客户清单', '中国铁塔股份有限公司锡林郭勒盟分公司', '内蒙古电力(集团)有限责任公司锡林郭勒电业局',
                     '内蒙古通用机打发票', '供电分局电费清单-铁塔公司', 'ocr9_words', 'ocr10_words', '中国移动通信集团内蒙古有限公司锡林郭勒分公司','中国铁塔股份有限公司呼和浩特市']
        ocr9_words = ['基站名称', '单价']
        ocr10_words = ['电费分割比例', '移动', '电费分摊比例', '联通', '电信','比例','电表户号']
        ocr11_words = ['基站名称', '读数', '电表户号', '总电量']
        type = 0
        for itemIndex in range(len(data['data']['items'])):
            content = str(data['data']['items'][itemIndex]['content']).strip()
            content = content.replace("（","(").replace("）",")")
            # if '(' in content:
            #     content = content.split('(')[0]
            for k in key_words:
                if content and k in content:
                    if key_words.index(k) == 11:
                        return 1
                    else:
                        return key_words.index(k) + 1
        for number in range(len(data["data"]["tables"])):
            for i in data["data"]["tables"][number]["cells"]:
                content = str(i["content"]).strip()
                for k in key_words:
                    if content and k in content:
                        if key_words.index(k) == 11:
                            return 1
                        else:
                            return key_words.index(k) + 1
        # 没有表头的特殊识别方法
        if type == 0:
            key_list = []
            ocr9_num = 0  # 固化符合的个数
            ocr10_num = 0 # 分摊比例符合的个数
            ocr11_num = 0  #
            column = data['data']['tables'][0]['column']  # 获取表格列数
            result_ocr = data['data']['tables'][0]['cells']  # 获取关键字结果
            for result in result_ocr:  # 识别结果整理成列表
                result['content'] = result['content'].replace(' ', '').replace('|', '').replace('\n', '')
                if '电费分摊比例' in result['content']:
                    key_list.append('电费分摊比例')
                if '电费分割比例' in result['content']:
                    key_list.append('电费分割比例')
                if '移动' in result['content']:
                    if '移动' not in key_list:
                            key_list.append('移动')
                if '联通' in result['content']:
                    key_list.append('联通')
                if '电信' in result['content']:
                    key_list.append('电信')
                if '基站名称' in result['content']:
                    key_list.append('基站名称')
                if '单价' in result['content']:
                    key_list.append('单价')
                if '总电量' in result['content']:
                    key_list.append('总电量')
                if '读数' in result['content']:
                    key_list.append('读数')
                if '电表户号' in result['content']:
                    key_list.append('电表户号')
            # key_list = key_list[:column - 1]
            for k in key_list:
                if k in ocr9_words:
                    ocr9_num += 1
                if k in ocr10_words:
                    ocr10_num += 1
                if k in ocr11_words:
                    ocr11_num += 1
            if ocr9_num >= 2:
                type=9
            if ocr10_num>=4:
                type=10
            if ocr11_num >= 4:
                type = 12
        return type

    @staticmethod
    def get_ocr_bill_ident(data):
        '''
        根据列名称判断票据类型
        :param data:
        :return:
        '''
        table_cells = data['data']['tables'][0]['cells']
        column = data['data']['tables'][0]['column']  # 获取表格列数
        content_list = ''
        sql_where = ''
        zhPattern = re.compile(u'[\u4e00-\u9fa5]+')
        for cell in table_cells[0:column]:
            if cell['content'] != '' and cell['content'] and cell['content'] != '-':
                 content = cell['content'].replace(' ', '').replace('|', '').replace('\n', '')
                 match = zhPattern.search(content)
                 if not match:  # 不包含汉字，标识为不是表头数据
                     break
                 if any(e in content for e in  ['公司','汇总']):  # 识别为表头特定数据，跳出
                     continue
                 content_list += content + ','
                 sql_where += " column_name like '%s' and" %('%' + content+'%')
                 if '电费结算清单' in sql_where:
                    sql_where = " column_name like '%电费结算清单%' and"
                    break
        sql_where = sql_where[:-3]
        # print(content_list)
        sql = 'select * from rpa_nm_bill_ident where ' + sql_where
        ident = PyMysql().get_db_data(sql)
        if ident:
            print('1-【识别票据类型信息成功】')
        return ident[0]


    # 统一调用识别
    @staticmethod
    def billOCR(bill_number, path, filename, type):
        try:
            """ 识别稽核图片\r\n
                path -- (list类型)文件(可能有多个图片拼接)的绝对路径
                filename -- (str类型)附件名称
                type -- (int类型)
            """
            result = {'success': 1, 'data': None}
            first_img_path = path[0]
            api_auth_pubkey = ConfigEnum.ocr_api_pubkey.value
            app_auth_secretkey = ConfigEnum.ocr_app_secretkey.value
            # try:
            with open(first_img_path, 'rb') as f:
                base64_data = str(base64.b64encode(f.read()), 'utf-8')
                f.close()
            headerData = Ocr().GenerateHeader(api_auth_pubkey, app_auth_secretkey)
            file_type = 0
            for i in range(3):
                try:
                    data = Ocr().callOcrApi(headerData, base64_data, True)
                    file_type = Ocr().getOcrType(data)
                    break
                except:
                    continue
            if file_type == 0:
                for i in range(3):
                    try:
                        data = Ocr().callOcrApi(headerData, base64_data, True)
                        file_type = Ocr().getOcrType(data)
                        break
                    except:
                        continue
            is_nm_rpa = False
            if file_type == 0 :
                is_nm_rpa = True
                mainModule().getLogging('main.py').info('开始二期票据识别')
                ident = Ocr().get_ocr_bill_ident(data)
                is_table = True
                if ident.get('is_handle') == 2 :  # 自定义票据类型，重新获取表格数据
                    mainModule().getLogging('main.py').info('自定义票据类型，重新获取表格数据!')
                    is_table = False
                    # 查询自定义模板对应的key
                    authInfo = PyMysql().get_db_data('select * from  rpa_nm_auth where bill_ident_id = %s' %ident.get('id') )[0]
                    headerData = Ocr().GenerateHeader(authInfo.get('api_auth_pubkey'), authInfo.get('app_auth_secretkey'))
                    data = Ocr().callOcrApi(headerData, base64_data)
                file_type = ident.get('mode_type')
            if file_type == 0:
                result['success'] = 1
                result['data'] = '无法判断识别类型'
            else:
                headerData1, is_table = Ocr().getHeaderData(file_type)
                all_data = []
                for img_path in path:
                    with open(img_path, 'rb') as f:
                        base64_data = str(base64.b64encode(f.read()), 'utf-8')
                        f.close()
                    for i in range(3):
                        try:
                            data = Ocr().callOcrApi(headerData1, base64_data, is_table)
                            all_data.append(data)
                            break
                        except:
                            continue
                if type == '1' or type == 1:
                    type = '报账点电费'
                if type == '2' or type == 2:
                    type = '核销'
                if type == '3' or type == 3:
                    type = '电费固化'
                if len(all_data) == 0:
                    for img_path in path:
                        with open(img_path, 'rb') as f:
                            base64_data = str(base64.b64encode(f.read()), 'utf-8')
                            f.close()
                        for i in range(3):
                            try:
                                data = Ocr().callOcrApi(headerData1, base64_data, is_table)
                                all_data.append(data)
                                break
                            except:
                                continue
                if is_nm_rpa:
                    result_value = getattr(OcrUtils, file_type)(all_data, filename, bill_number, type,
                                                                ident.get('bill_type_name'), ident.get('is_handle'))
                else:
                    result_value = getattr(OcrUtils, 'OCR_type_' + str(file_type))(all_data, filename, bill_number, type)
                result['success'] = 0
                result['data'] = result_value
            # except Exception as e:
            #     result['success'] = 1
            #     print(e)
            return result
        except Exception as e:
            # print(e, ' ', e.__traceback__.tb_lineno)
            mainModule().getLogging('ocr.py').error(e, exc_info=True)

    @staticmethod
    def ocr_img_list(img_list, bill_number, type, attach_type):
        ocr_success = True
        ao_list = []
        o_list = []
        pname = ''
        c = 0
        for i in img_list:
            c += 1
            if not pname:
                o_list.append(i[1])
                pname = i[0]
            elif i[0] == pname:
                for o in o_list:
                    if pname not in o:
                        o_list.clear()
                        break
                o_list.append(i[1])
            else:
                ao_list.append([pname, o_list])
                pname = i[0]
                o_list = [i[1]]
            if c == len(img_list):
                ao_list.append([pname, o_list])
        for ocr_img in ao_list:
            if type != '3':
                if '附件1' in ocr_img[0] or '附件5' in ocr_img[0] or '附件6' in ocr_img[0] or '附件4' in ocr_img[0]:
                    continue
                if 3 == attach_type and '附件2' in ocr_img[0]:
                    continue
                if 2 == attach_type and '附件3' in ocr_img[0]:
                    continue
            ocr_result = Ocr().billOCR(bill_number, ocr_img[1], ocr_img[0], type)
            if ocr_result['success'] == 1:
                ocr_success = False
        return ocr_success

    """
    移动印章识别模块
    """
    @staticmethod
    def stamp_identify(img_path, name_list):
        result = {'success': 1, 'data': ''}
        # if img_path[-4:] =='.pdf':
        #     return result
        url = ConfigEnum.stamp_url.value

        with open(img_path, 'rb') as f:
            base64_data = str(base64.b64encode(f.read()), 'utf-8')
            f.close()
        # HeaderDict = dict()
        # HeaderDict['Authorization'] = '123'
        body = {"img": base64_data}
        # 正式
        headers = {'content-type': "application/json",
                   'Authorization': ConfigEnum.stamp_authorization.value, "type": "seal"}
        # 测试
        # headers = {'content-type': "application/json", 'Authorization': stamp_authorization,'type':'seal'}
        response = requests.post(url, data=json.dumps(body), headers=headers)
        if '500' in str(response.status_code):
            result['success'] = 1
        else:
            res_text = json.loads(response.text)
            # print(res_text)
            content = res_text['content']
            if len(content) > 0:
                for c in content:
                    for name in name_list:
                        if name in str(c):
                            # print('印章匹配成功：', name)
                            result['success'] = 0
                            result['data'] = content
                            break
        return result

